home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 23 / Amiga Format AFCD23 (Feb 1998, Issue 107).iso / -in_the_mag- / emulation / consoles / vision-8 / sources / x.c < prev   
C/C++ Source or Header  |  1997-12-12  |  14KB  |  462 lines

  1. /** Vision8: CHIP8 emulator *************************************************/
  2. /**                                                                        **/
  3. /**                                  X.c                                   **/
  4. /**                                                                        **/
  5. /** This file contains the X-Windows implementation                        **/
  6. /**                                                                        **/
  7. /** Copyright (C) Marcel de Kogel 1997                                     **/
  8. /** AmiWin adaption copyright (C) Lars Malmborg 1997                       **/
  9. /**     You are not allowed to distribute this software commercially       **/
  10. /**     Please, notify me, if you make any changes to this file            **/
  11. /****************************************************************************/
  12.  
  13. #include "CHIP8.h"
  14.  
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <signal.h>
  19. #ifndef _AMIGA
  20. #include <sys/time.h>
  21. #endif
  22. #include <X11/Xlib.h>
  23. #include <X11/Xutil.h>
  24. #include <X11/keysym.h>
  25.  
  26. #ifdef _AMIGA
  27. char *AmigaVersion="$VER: Vision-8 AmiWin 1.0 "__AMIGADATE__;
  28.  
  29. #include <pragmas/xlib_pragmas.h>
  30. extern struct Library *XLibBase;
  31.  
  32. #include <pragmas/xleshape_pragmas.h>
  33. extern struct Library *XLEShapeBase;
  34.  
  35. #include <pragmas/xmu2_pragmas.h>
  36. extern struct Library *Xmu2Base;
  37.  
  38. #include <pragmas/xt_pragmas.h>
  39. extern struct Library *XtBase;
  40.  
  41. #include <pragmas/xaw_pragmas.h>
  42. extern struct Library *XawBase;
  43. #endif
  44.  
  45. #define WIDTH   256
  46. #define HEIGHT  128
  47.  
  48. /* Windows title */
  49. static char Title[]="Vision-8 Unix/X 1.0";
  50.  
  51. static byte *DisplayBuf;          /* Screen buffer                          */
  52. static Display *Dsp;          /* Default display                        */
  53. static Window Wnd;          /* Our window                    */
  54. static Colormap DefaultCMap;      /* The display's default colours          */
  55. static XImage *Img;          /* Our image                              */
  56. static GC DefaultGC;          /* The default graphics context        */
  57. static int White,Black;          /* White and black colour values        */
  58. #ifdef MITSHM              /* SHM extensions                */
  59. #include <sys/ipc.h>
  60. #include <sys/shm.h>
  61. #include <X11/extensions/XShm.h>
  62. XShmSegmentInfo SHMInfo;
  63. int UseSHM=1;
  64. #endif
  65.  
  66. static int bpp;                   /* Bits per pixel of the display device   */
  67. static int uperiod=1;             /* Number of interrupts per screen update */
  68. static int sync=1;                /* If 0, do not sync emulation            */
  69. static long timer;                /* Timer value at previous interrupt      */
  70. static byte keybstatus[512];      /* If 1, specified key is being held down */
  71.  
  72. /****************************************************************************/
  73. /* Return the time elapsed in microseconds                                  */
  74. /****************************************************************************/
  75. static long ReadTimer (void)
  76. {
  77. #ifdef HAVE_CLOCK
  78.  return (long)((float)clock()*1000000.0/(float)CLOCKS_PER_SEC);
  79. #else
  80.  /* If clock() is unavailable, just return a large number */
  81.  static long a=0;
  82.  a+=1000000;
  83.  return a;
  84. #endif
  85. }
  86.  
  87. /****************************************************************************/
  88. /* Turn sound on                                                            */
  89. /****************************************************************************/
  90. void chip8_sound_on (void)
  91. {
  92. }
  93.  
  94. /****************************************************************************/
  95. /* Turn sound off                                                           */
  96. /****************************************************************************/
  97. void chip8_sound_off (void)
  98. {
  99. }
  100.  
  101. /****************************************************************************/
  102. /* Table to convert X-Windows key values to CHIP8 equivalents               */
  103. /****************************************************************************/
  104. static byte keyboard_table[512]=
  105. {
  106.   0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      /* 00 */
  107.   0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      /* 10 */
  108.   0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0,13,12, 4,16, 0,      /* 20 */
  109.   3, 2, 3, 4,13, 0, 0, 0,  0, 2, 0,15, 0, 0, 0, 0,      /* 30 */
  110.   0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      /* 40 */
  111.   0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0,14, 0, 0, 0, 0,      /* 50 */
  112.   0, 8, 0,12,10, 7,15, 0,  0, 5, 8, 9,10, 1,11, 6,      /* 60 */
  113.   7, 5,14, 9, 0, 0,16, 6,  1, 0,11, 0, 0, 0, 0, 0,      /* 70 */
  114.   0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      /* 80 */
  115.   0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      /* 90 */
  116.   0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      /* a0 */
  117.   0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      /* b0 */
  118.   0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      /* c0 */
  119.   0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      /* d0 */
  120.   0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      /* e0 */
  121.   0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0       /* f0 */
  122. };
  123.  
  124. /****************************************************************************/
  125. /* Parse keyboard events and update CHIP8 keyboard status                   */
  126. /****************************************************************************/
  127. static void check_keys (void)
  128. {
  129.  XEvent E;
  130.  unsigned long i;
  131.  int j;
  132.  while (XCheckWindowEvent(Dsp,Wnd,KeyPressMask|KeyReleaseMask,&E))
  133.  {
  134.   i=XLookupKeysym ((XKeyEvent*)&E,0);
  135.   if ((i&0xFFFFFF00)==0 || (i&0xFFFFFF00)==0xFF00)
  136.   {
  137.    if (E.type==KeyPress)
  138.    {
  139.     if (i==XK_Escape || i==XK_F10) chip8_running=0;
  140.     if (i==XK_F1) chip8_reset ();
  141.     keybstatus[i&511]=1;
  142.    }
  143.    else
  144.     keybstatus[i&511]=0;
  145.   }
  146.  }
  147.  memset (chip8_keys,0,sizeof(chip8_keys));
  148.  for (i=0;i<512;++i)
  149.  {
  150.   if (keybstatus[i])
  151.   {
  152.    j=keyboard_table[i];
  153.    if (j) chip8_keys[j-1]=1;
  154.   }
  155.  }
  156. }
  157.  
  158. /****************************************************************************/
  159. /* Update the display                                                       */
  160. /****************************************************************************/
  161. #define UPDATE_DISPLAY \
  162.  { \
  163.   PIXEL *p; \
  164.   int i,j; \
  165.   byte *q; \
  166.   p=(PIXEL *) DisplayBuf; \
  167.   q=chip8_display; \
  168.   for (i=0;i<32;++i,p+=WIDTH*3) \
  169.    for (j=0;j<64;++j,p+=4,q++) \
  170.    { \
  171.     p[WIDTH*0+0]=p[WIDTH*0+1]=p[WIDTH*0+2]=p[WIDTH*0+3]= \
  172.     p[WIDTH*1+0]=p[WIDTH*1+1]=p[WIDTH*1+2]=p[WIDTH*1+3]= \
  173.     p[WIDTH*2+0]=p[WIDTH*2+1]=p[WIDTH*2+2]=p[WIDTH*2+3]= \
  174.     p[WIDTH*3+0]=p[WIDTH*3+1]=p[WIDTH*3+2]=p[WIDTH*3+3]=(*q)? White:Black; \
  175.    } \
  176.  }
  177.  
  178. static void update_display (void)
  179. {
  180.  switch (bpp)
  181.  {
  182.   case 8:
  183.    #define PIXEL byte
  184.    UPDATE_DISPLAY
  185.    #undef PIXEL
  186.    break;
  187.   case 16:
  188.    #define PIXEL unsigned short
  189.    UPDATE_DISPLAY
  190.    #undef PIXEL
  191.    break;
  192.   case 32:
  193.    #define PIXEL unsigned
  194.    UPDATE_DISPLAY
  195.    #undef PIXEL
  196.    break;
  197.  }
  198. #ifdef MITSHM
  199.  if (UseSHM) XShmPutImage (Dsp,Wnd,DefaultGC,Img,0,0,0,0,WIDTH,HEIGHT,False);
  200.  else
  201. #endif
  202.  XPutImage (Dsp,Wnd,DefaultGC,Img,0,0,0,0,WIDTH,HEIGHT);
  203.  XFlush (Dsp);
  204. }
  205.  
  206. /****************************************************************************/
  207. /* Update keyboard and display, sync emulation with VDP clock               */
  208. /****************************************************************************/
  209. void chip8_interrupt (void)
  210. {
  211.  static int ucount=1;
  212.  long newtimer;
  213.  if (!--ucount)
  214.  {
  215.   ucount=uperiod;
  216.   update_display ();
  217.  }
  218.  check_keys ();
  219.  if (sync)
  220.  {
  221.   newtimer=ReadTimer ();
  222.   timer+=20000;
  223.   if ((newtimer-timer)<0)
  224.   {
  225.    do
  226.     newtimer=ReadTimer ();
  227.    while ((newtimer-timer)<0);
  228.   }
  229.   else timer=newtimer;
  230.  }
  231. }
  232.  
  233. /****************************************************************************/
  234. /** Deallocate all resources taken by InitMachine()                        **/
  235. /****************************************************************************/
  236. static void TrashMachine(void)
  237. {
  238.  if (Dsp && Wnd)
  239.  {
  240. #ifdef MITSHM
  241.   if (UseSHM)
  242.   {
  243.    XShmDetach (Dsp,&SHMInfo);
  244.    if (SHMInfo.shmaddr) shmdt (SHMInfo.shmaddr);
  245.    if (SHMInfo.shmid>=0) shmctl (SHMInfo.shmid,IPC_RMID,0);
  246.   }
  247.   else
  248. #endif
  249.   if (Img) XDestroyImage (Img);
  250.  }
  251.  if (Dsp) XCloseDisplay (Dsp);
  252. }
  253.  
  254. /****************************************************************************/
  255. /** Allocate resources needed by X-Windows-dependent code                  **/
  256. /****************************************************************************/
  257. static int InitMachine(void)
  258. {
  259.  Screen *Scr;
  260.  XSizeHints Hints;
  261.  XWMHints WMHints;
  262.  printf ("Initialising Unix/X drivers...\n");
  263.  printf ("  Opening display... ");
  264.  Dsp=XOpenDisplay (NULL);
  265.  if (!Dsp)
  266.  {
  267.   printf ("FAILED\n");
  268.   return 0;
  269.  }
  270.  Scr=DefaultScreenOfDisplay (Dsp);
  271.  White=WhitePixelOfScreen (Scr);
  272.  Black=BlackPixelOfScreen (Scr);
  273.  DefaultGC=DefaultGCOfScreen (Scr);
  274.  DefaultCMap=DefaultColormapOfScreen (Scr);
  275.  bpp=DefaultDepthOfScreen (Scr);
  276.  if (bpp!=8 && bpp!=16 && bpp!=32)
  277.  {
  278.   printf ("FAILED - Only 8,16 and 32 bpp displays are supported\n");
  279.   return 0;
  280.  }
  281.  if (bpp==32 && sizeof(unsigned)!=4)
  282.  {
  283.   printf ("FAILED - 32 bpp displays are only supported on 32 bit machines\n");
  284.   return 0;
  285.  }
  286.  printf ("OK\n  Opening window... ");
  287.  Wnd=XCreateSimpleWindow (Dsp,RootWindowOfScreen(Scr),
  288.                           0,0,WIDTH,HEIGHT,0,White,Black);
  289.  if (!Wnd)
  290.  {
  291.   printf ("FAILED\n");
  292.   return 0;
  293.  }
  294.  Hints.flags=PSize|PMinSize|PMaxSize;
  295.  Hints.min_width=Hints.max_width=Hints.base_width=WIDTH;
  296.  Hints.min_height=Hints.max_height=Hints.base_height=HEIGHT;
  297.  WMHints.input=True;
  298.  WMHints.flags=InputHint;
  299.  XSetWMHints (Dsp,Wnd,&WMHints);
  300.  XSetWMNormalHints (Dsp,Wnd,&Hints);
  301.  XStoreName (Dsp,Wnd,Title);
  302.  XSelectInput (Dsp,Wnd,FocusChangeMask|ExposureMask|KeyPressMask|KeyReleaseMask);
  303.  XMapRaised (Dsp,Wnd);
  304.  XClearWindow (Dsp,Wnd);
  305.  printf ("OK\n");
  306. #ifdef MITSHM
  307.  if (UseSHM)
  308.  {
  309.   printf ("  Using shared memory:\n    Creating image... ");
  310.   Img=XShmCreateImage (Dsp,DefaultVisualOfScreen(Scr),bpp,
  311.                        ZPixmap,NULL,&SHMInfo,WIDTH,HEIGHT);
  312.   if (!Img)
  313.   {
  314.    printf ("FAILED\n");
  315.    return 0;
  316.   }
  317.   printf ("OK\n    Getting SHM info... ");
  318.   SHMInfo.shmid=shmget (IPC_PRIVATE,Img->bytes_per_line*Img->height,
  319.               IPC_CREAT|0777);
  320.   if (SHMInfo.shmid<0)
  321.   {
  322.    printf ("FAILED\n");
  323.    return 0;
  324.   }
  325.   printf ("OK\n    Allocating SHM... ");
  326.   Img->data=SHMInfo.shmaddr=shmat(SHMInfo.shmid,0,0);
  327.   DisplayBuf=Img->data;
  328.   if (!DisplayBuf)
  329.   {
  330.    printf ("FAILED\n");
  331.    return 0;
  332.   }
  333.   SHMInfo.readOnly=False;
  334.   printf ("OK\n    Attaching SHM... ");
  335.   if (!XShmAttach(Dsp,&SHMInfo))
  336.   {
  337.    printf ("FAILED\n");
  338.    return 0;
  339.   }
  340.  }
  341.  else
  342. #endif
  343.  {
  344.   printf ("  Allocating screen buffer... ");
  345.   DisplayBuf=malloc(bpp*WIDTH*HEIGHT/8);
  346.   if (!DisplayBuf)
  347.   {
  348.    printf ("FAILED\n");
  349.    return 0;
  350.   }
  351.   printf ("OK\n  Creating image... ");
  352.   Img=XCreateImage (Dsp,DefaultVisualOfScreen(Scr),bpp,ZPixmap,
  353.               0,DisplayBuf,WIDTH,HEIGHT,8,0);
  354.   if (!Img)
  355.   {
  356.    printf ("FAILED\n");
  357.    return 0;
  358.   }
  359.  }
  360.  printf ("OK\n");
  361.  timer=ReadTimer ();
  362.  return 1;
  363. }
  364.  
  365. /****************************************************************************/
  366. /* Parse command line options and start emulation                           */
  367. /****************************************************************************/
  368. int main (int argc,char *argv[])
  369. {
  370.  FILE *f;
  371.  int i,j,k,misparm;
  372.  char *options[] = { "h","trap","up","ip","s",NULL };
  373.  char *program=NULL;
  374.  chip8_iperiod=15;
  375.  printf ("Vision-8: Portable CHIP8 emulator\n"
  376.          "Copyright (C) 1997  Marcel de Kogel\n");
  377.  for (i=1,k=0;i<argc;++i)
  378.  {
  379.   misparm=0;
  380.   if (*argv[i]!='-')
  381.    switch (k++)
  382.    {
  383.     case 0:  program=argv[i];
  384.              break;
  385.     default: printf("Excessive filename '%s'\n",argv[i]);
  386.              return 1;
  387.    }
  388.   else
  389.   {    
  390.    for (j=0;options[j];j++)
  391.     if (!strcmp(argv[i]+1,options[j])) break;
  392.    switch (j)
  393.    {
  394.     case 0:
  395.      printf ("Usage: v8 [options] <filename>\n"
  396.              "Available options are:\n"
  397.              " -h          - Print this help page\n"
  398. #ifdef DEBUG
  399.              " -trap <pc>  - Trap execution when PC reaches address <pc> [000]\n"
  400. #endif
  401.              " -up <value> - Select number of interrupts per screen update [1]\n"
  402.              " -ip <value> - Select number of opcodes per interrupt [15]\n"
  403.              " -s <value>  - Select synchronisation mode [1]\n"
  404.              "               0 - Do not sync emulation\n"
  405.              "               1 - Sync emulation to 50Hz clock\n");
  406.              return 0;
  407. #ifdef DEBUG
  408.     case 1:  i++;
  409.              if (i<argc) chip8_trap=strtoul(argv[i],NULL,16);
  410.              else misparm=1;
  411.              break;
  412. #endif
  413.     case 2:  i++;
  414.              if (i<argc) uperiod=atoi(argv[i]);
  415.              else misparm=1;
  416.              break;
  417.     case 3:  i++;
  418.              if (i<argc) chip8_iperiod=atoi(argv[i]);
  419.              else misparm=1;
  420.              break;
  421.     case 4:  i++;
  422.              if (i<argc) sync=atoi(argv[i]);
  423.              else misparm=1;
  424.              break;
  425.     default: printf ("Wrong option '%s'\n",argv[i]);
  426.              return 1;
  427.    }
  428.    if (misparm)
  429.    {
  430.     printf("%s: Missing parameter\n",argv[i-1]);
  431.     return 1;
  432.    }
  433.   }
  434.  }
  435.  if (!program)
  436.  {
  437.   puts ("No program name given\n");
  438.   return 1;
  439.  }
  440.  printf ("Opening CHIP8 program %s... ",program);
  441.  f=fopen (program,"rb");
  442.  if (!f)
  443.  {
  444.   puts ("FAILED");
  445.   return 1;
  446.  }
  447.  printf ("OK\n Reading... ");
  448.  i=fread (chip8_mem+0x200,1,4096-0x200,f);
  449.  fclose (f);
  450.  if (i==0)
  451.  {
  452.   puts ("File is empty");
  453.   return 1;
  454.  }
  455.  printf ("%d bytes loaded\n",i);
  456.  if (!InitMachine())                            /* Initialise X-Windows     */
  457.   return 1;                                     /* driver                   */
  458.  chip8 ();                                      /* start emulation          */
  459.  TrashMachine ();                               /* Deallocate resources     */
  460.  return 0;                                      /* all done                 */
  461. }
  462.